Skip to content

Conversation

guillesd
Copy link
Collaborator

@guillesd guillesd commented Oct 22, 2025

The idea of this PR is to make this tool a bit more useful (and visually appealing). I think generally it is good to have some better profiling tools to explore queries.

EDIT: Initially it was only about the query graph visuals, but I decided to expose the profiling functions enabled in the C++ API (similar to what the Go client does with the C API).

To use the tool:

  1. Build this branch (see https://duckdb.org/docs/stable/dev/building/python)
  2. Run the following in DuckDB
PRAGMA enable_profiling = 'json';
PRAGMA profiling_output = './tmp/profile.json';
SELECT ... FROM ...;
  1. Run the script (I do it with uv):
uv run python -m duckdb.query_graph tmp/complex_profile.json

If you want to use the profiling within the client:

import duckdb

con = duckdb.connect()
con.enable_profiling()
con.execute("select 42")
profile_info = con.get_profiling_information()
# optionally
con.disable_profiling()

WIP: Now you can expose translate_json_to_html from duckdb.query_graph and do everything within the python process natively:

from duckdb.query_graph import translate_json_to_html #maybe some better naming here

translate_json_to_html(input_text = profile_info, output_file = 'tmp/profile.html')

Which should yield something like the following screenshot:
Screenshot 2025-10-22 at 17 18 02

@guillesd guillesd marked this pull request as draft October 22, 2025 15:19
@guillesd
Copy link
Collaborator Author

The problem I'm facing now is that the profiling exposed by the API doesn't seem to have the float precision in CPU Time and overall Latency, and has some differences:

{
    "query_name": "",
    "total_bytes_written": 0,
    "latency": 0.0,
    "total_bytes_read": 0,
    "cumulative_rows_scanned": 0,
    "system_peak_buffer_memory": 0,
    "cumulative_cardinality": 0,
    "rows_returned": 0,
    "cpu_time": 0.0,
    "result_set_size": 0,
    "extra_info": {},
    "system_peak_temp_dir_size": 0,
    "blocked_thread_time": 0.0,
    "children": [
        {
            "operator_timing": 0.00003275,
            "operator_rows_scanned": 0,
            "operator_name": "PROJECTION",
            "operator_cardinality": 1,
            "cumulative_rows_scanned": 0,
            "cumulative_cardinality": 0,
            "cpu_time": 0.0,
            "result_set_size": 4,
            "operator_type": "PROJECTION",
            "extra_info": {
                "Projections": "42",
                "Estimated Cardinality": "1"
            },
            "children": [
                {
                    "operator_type": "DUMMY_SCAN",
                    "extra_info": {},
                    "cumulative_cardinality": 0,
                    "cumulative_rows_scanned": 0,
                    "operator_cardinality": 1,
                    "operator_rows_scanned": 0,
                    "operator_timing": 0.000005333,
                    "result_set_size": 4,
                    "cpu_time": 0.0,
                    "operator_name": "DUMMY_SCAN",
                    "children": []
                }
            ]
        }
    ]
}

Versus the same query using the PRAGMA approach within SQL:

{
    "total_bytes_written": 0,
    "total_bytes_read": 0,
    "rows_returned": 1,
    "latency": 0.004957334,
    "result_set_size": 4,
    "cumulative_rows_scanned": 0,
    "cpu_time": 0.000059875000000000005,
    "extra_info": {},
    "system_peak_buffer_memory": 0,
    "blocked_thread_time": 0.0,
    "cumulative_cardinality": 2,
    "system_peak_temp_dir_size": 0,
    "query_name": "select 42;",
    "children": [
        {
            "total_bytes_written": 0,
            "result_set_size": 4,
            "operator_timing": 0.000030667,
            "operator_rows_scanned": 0,
            "cumulative_rows_scanned": 0,
            "operator_cardinality": 1,
            "operator_type": "PROJECTION",
            "total_bytes_read": 0,
            "operator_name": "PROJECTION",
            "cpu_time": 0.000059875000000000005,
            "extra_info": {
                "Projections": "42",
                "Estimated Cardinality": "1"
            },
            "cumulative_cardinality": 2,
            "children": [
                {
                    "cumulative_cardinality": 1,
                    "extra_info": {},
                    "operator_name": "DUMMY_SCAN",
                    "cpu_time": 0.000029208,
                    "cumulative_rows_scanned": 0,
                    "operator_rows_scanned": 0,
                    "operator_timing": 0.000029208,
                    "result_set_size": 4,
                    "total_bytes_read": 0,
                    "operator_type": "DUMMY_SCAN",
                    "total_bytes_written": 0,
                    "operator_cardinality": 1,
                    "children": []
                }
            ]
        }
    ]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant